/*学习不定参宏函数*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdarg.h> 
#include <stdlib.h>
// 不定参数宏
#define LOG(fmt, ...) printf("[%s:%d]" fmt, __FILE__, __LINE__, ##__VA_ARGS__);
// ## 其作用是处理可变参数为空的情况，避免编译错误

// C语言函数中不定参的使用，不定参数据的访问操作
void printNum(int count, ...) // 第一个参数就是参数的个数，第二个参数就是... ,我们不确定参数的个数
{
    va_list ap;          // 定义一个可变参数列表类型的变量
    va_start(ap, count); // 初始化可变参数列表的遍历指针，获取指定参数的起始地址，这里就是获取count参数后第一个参数的起始地址
    for (int i = 0; i < count; i++)
    {
        int num = va_arg(ap, int); // 从可变参数列表中获取下一个对应类型的参数
        printf("\n");
        printf("param[%d]:%d\n",i,num); // 输出参数值
    }
    va_end(ap); // 结束可变参数列表的遍历,将ap指针置空
}

//模拟printf函数，不定参的使用
void myprintf(const char *fmt, ...)
{
    va_list ap;          
    va_start(ap, fmt); //获取指定参数的起始地址，这里就是获取fmt参数后第一个参数的起始地址
    char*res;
    int ret=vasprintf(&res, fmt, ap); //将格式化字符串fmt和可变参数ap转换成字符串
    if(ret!=-1)//说明我们是成功组织了的
    {
        printf("%s", res); //输出字符串
        free(res); //释放内存
    }
    va_end(ap);

}





int main()
{
    myprintf("%s-%d\n", "kaizi", 666); // 输出kaizi-666
    //LOG("kaizi");
    //printNum(3, 1, 2, 3); // 输出1 2 3
    //printNum(2, 4, 5); // 输出4 5

    return 0;
}

/*
LOG(fmt, ...)：宏名称是 LOG，它接受一个固定参数 fmt（格式字符串），后面是 ... 表示可以传入任意数量的额外参数（不定参）。

printf("[%s:%d]"fmt, __FILE__, __LINE__, __VA_ARGS__);

宏体中调用了 printf。

"[%s:%d]"fmt：格式化字符串，将会被拼接成如 "[main.c:10]%s-%d\n"。

__FILE__：这是一个预定义宏，表示当前源文件的名称（如 main.c）。

__LINE__：当前所在的行号。

__VA_ARGS__：表示传入的不定参数部分。

使用举例

LOG("%s-%d\n", "kaizi", 666);
预处理展开后会变成类似这样：
printf("[%s:%d]%s-%d\n", __FILE__, __LINE__, "kaizi", 666);

我们的[%s:%d]这个是固定的文件名和行号的输出操作

然后我们的fmt输出的就是%s-%d\n，kaizi和666就是不定参数部分
*/